package com.seari.config;

import com.seari.shiro.JwtFilter;
import com.seari.shiro.JwtRealm;

import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Shiro配置信息
 */
@Configuration
public class ShiroConfig
{
	 private static final Logger LOG = LoggerFactory.getLogger(ShiroConfig.class);
	 
	    @Bean
	    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
	        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
	        shiroFilterFactoryBean.setSecurityManager(securityManager);

	        Map<String, Filter> filterMap = new HashMap<>();
	        filterMap.put("jwt", new JwtFilter());
	        shiroFilterFactoryBean.setFilters(filterMap);
	        
	        LinkedHashMap<String,String> filterChainDefinitionMap = new LinkedHashMap<>();
	        //注意过滤器配置顺序 不能颠倒
	        //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了，登出后跳转配置的loginUrl
	        filterChainDefinitionMap.put("/api/logout","logout");
	        // 配置不会被拦截的链接 顺序判断
	        filterChainDefinitionMap.put("/materialCaregory/**", "anon");
	        filterChainDefinitionMap.put("/mcIn/**", "anon");
	        filterChainDefinitionMap.put("/account/**", "anon");

	        filterChainDefinitionMap.put("/druid/**", "anon");
	        filterChainDefinitionMap.put("/static/**", "anon");
	        filterChainDefinitionMap.put("/api/login", "anon");
	        filterChainDefinitionMap.put("/api/unauthorized", "anon");
	        filterChainDefinitionMap.put("/api/incorrectCredentials", "anon");
	        filterChainDefinitionMap.put("/api/unknownAccount", "anon");
	        filterChainDefinitionMap.put("/api/lockedAccount", "anon");
	        filterChainDefinitionMap.put("/api/expiredCredentials", "anon");
	        filterChainDefinitionMap.put("/api/unsupportedToken", "anon");
	        filterChainDefinitionMap.put("/api/authentication", "anon");
	        filterChainDefinitionMap.put("/api/kaptcha", "anon");
	        filterChainDefinitionMap.put("/api/**", "jwt");
	        filterChainDefinitionMap.put("/**", "anon");
	        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
	        return shiroFilterFactoryBean;
	    }

	    /**
	     * 配置自定义的权限登录器
	     * @return
	     */
	    @Bean
	    public JwtRealm jwtRealm(){
	        JwtRealm jwtRealm = new JwtRealm();
	        //jwtRealm.setCacheManager(ehCacheManager());
	        //开启权限缓存
	        jwtRealm.setAuthorizationCacheName(JwtRealm.AUTHORIZATION_CACHE);
	        jwtRealm.setAuthorizationCachingEnabled(true);
	        //认证缓存
	        jwtRealm.setAuthenticationCacheName(JwtRealm.AUTHRANTICATION_CACHE);
	        jwtRealm.setAuthenticationCachingEnabled(true);
	        return jwtRealm;
	    }


	    /**
	     * shiro缓存管理器;
	     * 需要注入对应的其它的实体类中：
	     * 1、安全管理器：securityManager
	     * 可见securityManager是整个shiro的核心
	     * @return
	     */
//	    @Bean
//	    public EhCacheManager ehCacheManager(){
//	        LOG.info("start ehCacheCacheManager function");
//	        EhCacheManager ehCacheManager = new EhCacheManager();
//	        ehCacheManager.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
//	        LOG.info("end ehCacheCacheManager function");
//	        return ehCacheManager;
//	    }

	    /**
	     * 设置cookie保存时长对象
	     * @return
	     */
	    @Bean
	    public SimpleCookie rememberMeCookie(){
	        LOG.info("start simpleCookie function");
	        //这个参数是cookie的名称，对应前端的checkbox的name = rememberMe
	        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
	        //记住我cookie生效时间30天 ,单位秒;
	        simpleCookie.setMaxAge(259200);
	        LOG.info("end simpleCookie function");
	        return simpleCookie;
	    }

	    /**
	     * cookie管理对象;
	     * @return
	     */
	    @Bean
	    public CookieRememberMeManager rememberMeManager(){
	        LOG.info("start rememberMeManager function");
	        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
	        cookieRememberMeManager.setCookie(rememberMeCookie());
	        LOG.info("end rememberMeManager function");
	        return cookieRememberMeManager;
	    }


	    /**
	     * 配置核心安全事务管理器
	     * @return
	     */
	    @Bean
	    public SecurityManager securityManager(){
	        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
	        //注入认证/权限
	        securityManager.setRealm(jwtRealm());
	        //注入缓存管理器;
	        //securityManager.setCacheManager(ehCacheManager());
	        //注入记住我管理器;
	        securityManager.setRememberMeManager(rememberMeManager());
	        return securityManager;
	    }


	    @Bean
	    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
	        return new LifecycleBeanPostProcessor();
	    }

	    @Bean
	    @ConditionalOnMissingBean
	    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
	        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
	        creator.setProxyTargetClass(true);
	        return creator;
	    }

	    /**
	     * 开启shiro aop注解支持，使用代理方式;所以需要开启代码支持;
	     * @param securityManager
	     * @return
	     */
	    @Bean
	    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
	        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
	        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
	        return authorizationAttributeSourceAdvisor;
	    }
	    
	    
}
